feat: portable AGENTS.md output (--agents, --all) + non-interactive --yes#2
Conversation
…ve --yes - compose.js: buildAgentsBlock/writeRulesAgentsMd emit AGENTS.md as plain markdown (Cursor, Copilot, Codex, Claude Code) with a single H1; module headings demoted to ##. Managed-block markers preserve hand-edited content on regeneration; foreign files are appended to, not clobbered. - cli.js: --agents, --all, --yes/-y, -h/--help, mutual-exclusion check, and an always-on token size warning (>~2000 tokens). - tests/agents.test.js: create / regen-preserves-user-content / foreign-file / plain-markdown (no globs/alwaysApply) coverage. - package.json: fix test glob to tests/*.test.js (CI needs no bash globstar), bump to 1.2.0, broaden description + keywords (agents-md, claude, copilot...). - CI: GitHub Actions test matrix (Node 18/20/22) + non-interactive smoke test.
📝 WalkthroughWalkthroughAdds managed ChangesManaged AGENTS.md workflow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant src_cli_js as src/cli.js
participant src_compose_js as src/compose.js
participant modules as modules
participant AGENTS_md as AGENTS.md
User->>src_cli_js: run --agents or --all
src_cli_js->>src_compose_js: writeRulesAgentsMd(moduleIds, cwd, opts)
src_compose_js->>modules: read selected module markdown
src_compose_js->>AGENTS_md: create, replace, or append managed block
src_compose_js-->>src_cli_js: write result and status
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Kilo Code Review could not run — your account is out of credits. Add credits or switch to a free model to enable reviews on this change. |
There was a problem hiding this comment.
Code Review
This pull request introduces support for generating a portable AGENTS.md file compatible with multiple AI editors, adding new CLI flags (--agents, --all, --yes), token estimation warnings, and safe block-based updates. The review feedback highlights critical improvements: skipping interactive prompts entirely in non-interactive mode (--yes) to prevent CI hangs, validating both start and end markers in AGENTS.md to avoid silent data loss, and demoting all markdown heading levels incrementally to preserve document hierarchy.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| return tokens; | ||
| }; | ||
|
|
||
| // --legacy: single .cursorrules file |
There was a problem hiding this comment.
In non-interactive mode (--yes / -y), the CLI should not prompt the user. Currently, if --legacy and --yes are both used and .cursorrules already exists, the tool will still prompt the user to overwrite, causing scripts or CI pipelines to hang indefinitely.
Please update the check on line 134 to skip the prompt when isYes is true:
if (existsSync(outFile) && !isYes) {Note: The same issue exists for the default mode prompt on line 191 (if (existingMdc.length > 0) {), which is outside the current diff hunks. Please also update that line to skip the prompt when isYes is true:
if (existingMdc.length > 0 && !isYes) {| async function resolveForeignDecision(isYes) { | ||
| const p = join(process.cwd(), 'AGENTS.md'); | ||
| if (!existsSync(p)) return () => 'append'; | ||
| if (readFileSync(p, 'utf8').includes(AGENTS_START)) return () => 'append'; |
There was a problem hiding this comment.
If AGENTS.md contains AGENTS_START but is missing AGENTS_END (or they are out of order), the file is malformed. Currently, resolveForeignDecision only checks for the presence of AGENTS_START, which means it will bypass the prompt and return 'append'. On the next run, writeRulesAgentsMd will find the first AGENTS_START and the newly appended AGENTS_END, and replace everything in between—silently deleting any user content that was added between them.
We should ensure both markers are present and valid before bypassing the prompt.
const content = readFileSync(p, 'utf8');
const startIdx = content.indexOf(AGENTS_START);
const endIdx = content.indexOf(AGENTS_END);
const hasValidMarkers = startIdx !== -1 && endIdx !== -1 && endIdx > startIdx;
if (hasValidMarkers) return () => 'append';| AGENTS_START, | ||
| } from './compose.js'; |
| // Demote module headings so AGENTS.md has a single top-level H1. | ||
| return content.replace(/^# /gm, '## '); |
There was a problem hiding this comment.
Currently, only top-level # headings are demoted to ##. This breaks the heading hierarchy within the module (e.g., any existing ## sub-headings in the module file will now be at the same level as the demoted top-level heading, becoming sibling headings instead of child headings).
We should demote all headings by shifting their levels down by one (e.g., # -> ##, ## -> ###, etc.) using a regex that matches any heading level followed by a space.
| // Demote module headings so AGENTS.md has a single top-level H1. | |
| return content.replace(/^# /gm, '## '); | |
| // Demote all module headings by one level to preserve document hierarchy. | |
| return content.replace(/^(#+)(?=\s)/gm, '#$1'); |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
package.json (1)
3-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd
enginesfield to enforce Node 18+ at install time.The README and CLI both require Node 18+, but
package.jsonlacks anenginesfield. Adding"engines": { "node": ">=18" }would let npm warn users before runtime."engines": { "node": ">=18" }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@package.json` around lines 3 - 4, Add an engines constraint to package.json so installs warn early for unsupported runtimes. Update the package metadata to include an engines field with Node set to >=18, keeping it alongside the existing version/description entries so the CLI and README’s Node 18+ requirement is enforced at install time.README.md (1)
99-121: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd language specifier to the
src/tree code block.Line 112's fenced code block has no language tag, triggering markdownlint
MD040. Addtextafter the opening backticks.- ``` + ```text src/🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 99 - 121, The fenced code block under the “How it works” section is missing a language specifier and triggers markdownlint MD040. Update that `src/` tree block to use a `text` fence so the Markdown is explicitly typed. Locate the block near the “How it works” heading and adjust the opening backticks accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci.yml:
- Around line 17-20: The workflow uses mutable action tags for actions/checkout
and actions/setup-node, so update both jobs to pin these third-party actions to
immutable full commit SHAs instead of `@v4`. Keep the existing steps in the ci
workflow, but replace the version tags for checkout and setup-node everywhere
they appear so the job definitions are locked to specific revisions.
- Around line 1-8: Add an explicit workflow-level least-privilege permissions
block in the CI workflow so the default GITHUB_TOKEN does not get broader access
than needed. Update the workflow definition near the existing
on/push/pull_request configuration to include a permissions setting that limits
the job to read-only repository contents, and keep the change scoped at the
workflow level since the jobs only need to check out code and run local
commands.
- Line 17: Update both actions/checkout usages in the CI workflow to disable
token persistence by setting persist-credentials to false. The issue affects
each checkout step in the workflow, so adjust both invocations consistently to
avoid storing repo credentials in the local git config when the jobs only read
code.
In `@src/cli.js`:
- Line 44: The --yes flag in src/cli.js only skips module selection today, but
it still allows later prompts in the legacy .cursorrules flow and the default
.cursor/rules/ flow. Update the prompt guards around the relevant CLI branches
so that the --yes/non-interactive path bypasses every confirmation, including
the legacy .cursorrules prompt and the .cursor/rules/ overwrite/selection
prompt. Use the existing CLI flag handling and prompt sites in the main command
flow to ensure --legacy --yes and plain --yes both run fully non-interactively.
- Around line 172-180: In the `isAll` flow inside `src/cli.js`, the AGENTS
foreign-file decision is resolved after `writeRulesMdc(selected)`, which can
leave `.cursor/rules` modified even when the user cancels. Move the
`resolveForeignDecision(isYes)` / `writeRulesAgentsMd(...)` decision ahead of
`writeRulesMdc(selected)`, and only proceed to write any `.mdc` files when the
AGENTS action is not cancelled; keep the existing `actionVerb`,
`writeRulesAgentsMd`, and `writeRulesMdc` behavior otherwise unchanged.
- Around line 220-224: resolveForeignDecision currently suppresses the prompt
based only on AGENTS_START, so a partial or stray marker can be misclassified as
a managed block. Update the AGENTS.md check in resolveForeignDecision to verify
a complete managed block by requiring both the start and end markers before
returning append, and keep the existing isYes fallback behavior unchanged.
In `@src/compose.js`:
- Around line 149-152: The managed-block lookup in compose.js should find the
end marker only after the start marker, not by searching the whole file first.
Update the existing.indexOf logic in the block that uses AGENTS_START and
AGENTS_END so the AGENTS_END search begins after startIdx, and keep the existing
update path in compose.js from misclassifying content when user text contains
the end marker string.
---
Nitpick comments:
In `@package.json`:
- Around line 3-4: Add an engines constraint to package.json so installs warn
early for unsupported runtimes. Update the package metadata to include an
engines field with Node set to >=18, keeping it alongside the existing
version/description entries so the CLI and README’s Node 18+ requirement is
enforced at install time.
In `@README.md`:
- Around line 99-121: The fenced code block under the “How it works” section is
missing a language specifier and triggers markdownlint MD040. Update that `src/`
tree block to use a `text` fence so the Markdown is explicitly typed. Locate the
block near the “How it works” heading and adjust the opening backticks
accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 780882e4-70d9-47f1-b31a-c0c3c867dbe3
📒 Files selected for processing (6)
.github/workflows/ci.ymlREADME.mdpackage.jsonsrc/cli.jssrc/compose.jstests/agents.test.js
…ning Addresses the review findings on this PR (Gemini / CodeRabbit / Kilo): - --yes now skips every prompt. --legacy --yes and the default mode no longer block on the overwrite prompt, so non-interactive/CI runs can't hang (the flag's whole purpose). - --all resolves the AGENTS.md decision and writes it first, so cancelling aborts before any .mdc files are written (no half-done state). - AGENTS.md updates require a valid, ordered start/end marker pair (findManagedBlock); an orphaned start marker is treated as a foreign file instead of being silently corrupted, and the end marker is matched after the start. - Heading demotion is incremental (h1->h2 ... capped at h6) and skips fenced code blocks (demoteHeadings), preserving each module's hierarchy. Hardening & hygiene: - CI: least-privilege permissions, persist-credentials:false, actions pinned to commit SHAs. - Add MIT LICENSE (package.json already declares MIT). - tests/fixes.test.js: 10 regression tests incl. CLI subprocess checks that fail if --yes ever blocks on a prompt. Suite now 31/31 green.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
docs/demo.tape (1)
12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHardcoded absolute path limits portability.
/workspaces/cursor-rules/src/cli.jsonly resolves inside a specific devcontainer layout; regenerating the demo elsewhere will break this shell override.♻️ Suggested fix using a relative path
-Type 'npx() { shift; node /workspaces/cursor-rules/src/cli.js "$@"; }' +Type 'npx() { shift; node "$(pwd)/../../src/cli.js" "$@"; }'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/demo.tape` at line 12, The npx shell override in the demo uses a hardcoded absolute path, which makes the example non-portable. Update the override in the demo script to invoke the CLI through a relative path from the repository root instead of `/workspaces/cursor-rules/src/cli.js`, so the `npx()` wrapper continues to work regardless of the local checkout location.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@docs/demo.tape`:
- Line 12: The npx shell override in the demo uses a hardcoded absolute path,
which makes the example non-portable. Update the override in the demo script to
invoke the CLI through a relative path from the repository root instead of
`/workspaces/cursor-rules/src/cli.js`, so the `npx()` wrapper continues to work
regardless of the local checkout location.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dbc41c6b-4ca4-4149-9ef0-1dd3abebfd33
⛔ Files ignored due to path filters (1)
docs/demo.gifis excluded by!**/*.gif
📒 Files selected for processing (6)
.github/workflows/ci.ymlLICENSEdocs/demo.tapesrc/cli.jssrc/compose.jstests/fixes.test.js
🚧 Files skipped from review as they are similar to previous changes (3)
- .github/workflows/ci.yml
- src/compose.js
- src/cli.js
What
Adds portable
AGENTS.mdoutput so one source produces rules for Cursor, GitHub Copilot, Codex, and Claude Code — alongside the existing.cursor/rules/*.mdcand.cursorrules. Also adds a non-interactive mode for scripting/CI and the project's first CI workflow.Flags
.cursor/rules/*.mdc(unchanged)--agentsAGENTS.mdat repo root (portable, cross-tool)--all.mdcandAGENTS.md, one pass--legacy.cursorrules(unchanged)--yes,-y-h,--help--agents,--legacy,--allare mutually exclusive (clear error otherwise).Design notes
AGENTS.mdis plain markdown — deliberately not the Cursor.mdcYAML frontmatter (globs/alwaysApplyare Cursor-specific). Module# Titles are demoted to##so the file has a single H1.<!-- cursor-compose:start/end -->): regenerating only replaces the managed block, so hand-edits outside it are preserved. A pre-existing AGENTS.md without markers is appended to (or, interactively, overwrite/cancel) — never silently clobbered.Tests / CI
tests/agents.test.js: create, regenerate-preserves-user-content, foreign-file handling, and a plain-markdown assertion (noglobs:/alwaysApply:). Suite now 21 tests, all passing.npm testglob totests/*.test.jsso it runs without bashglobstar(the old**matched nothing under GitHub Actions' default shell).--yessmoke test that asserts both outputs and that no frontmatter leaks intoAGENTS.md.Docs / meta
package.json: bumped to1.2.0, broadened description + keywords (agents-md,claude,copilot,codex, …). Not published to npm — version bump only.Verification
npm testgreen (21/21). Manual smoke in a sample Next.js project confirmed:--all --yeswrites 3.mdc+AGENTS.md; regeneration preserves a hand-added section;--helpand mutual-exclusion error behave as expected.Summary by CodeRabbit
AGENTS.mdwith safe managed sections.AGENTS.md, legacy rules, or both, including non-interactive--yes.AGENTS.mdblock.AGENTS.mdis plain markdown (no unwanted frontmatter).LICENSE.